﻿using System;
using System.Collections.Generic;
using System.Text;
using EnvDTE80;
using EnvDTE;

namespace dFactor2.CodeHelpers
{
    public class Methods : CodeHelperBase
    {
        public Methods(DTE2 applicationObject) : base(applicationObject) { }

        //Experimental
        public void CreateDelegate()
        {
            CodeFunction codeFunc = GetCurrentCodeElement<CodeFunction>(vsCMElement.vsCMElementFunction);
            if (codeFunc == null)
            {
                return;
            }

            CodeClass2 parentClass = codeFunc.Parent as CodeClass2;
            CodeDelegate2 codeDel = (CodeDelegate2)parentClass.AddDelegate("atmpDelegate" + DateTime.Now.Second + "Delegate", codeFunc.Type.TypeKind, codeFunc, vsCMAccess.vsCMAccessPublic);

            foreach (CodeParameter funcParam in codeFunc.Parameters)
            {
                codeDel.AddParameter(funcParam.Name, funcParam.Type.TypeKind, -1);
            }

            EditPoint edtpnt = codeDel.GetStartPoint(vsCMPart.vsCMPartWhole).CreateEditPoint();
            edtpnt.Delete(codeDel.GetEndPoint(vsCMPart.vsCMPartWhole));
            edtpnt.Insert(codeFunc.Name + "Delegate");
            //((CodeElement)codeDel).Name = codeFunc.Name + "Delegate";
            //codeDel.Name = codeFunc.Name + "Delegate";
        }

        public void SurroundWithTryBlock(bool includeCatch, bool includeFinally)
        {
            CodeFunction codeFunc = GetCurrentCodeElement<CodeFunction>(vsCMElement.vsCMElementFunction);
            if (codeFunc == null)
            {
                return;
            }

            EditPoint edtpntStart = codeFunc.GetStartPoint(vsCMPart.vsCMPartBody).CreateEditPoint();
            EditPoint edtpntEnd = codeFunc.GetEndPoint(vsCMPart.vsCMPartBody).CreateEditPoint();

            edtpntStart.Insert("try {\n");

            edtpntEnd.Insert("\n}\n");

            if (includeCatch)
            {
                edtpntEnd.Insert("catch \n{ throw; }\n");
            }

            if (includeFinally)
            {
                edtpntEnd.Insert("finally {}");
            }

            edtpntEnd.SmartFormat(codeFunc.StartPoint);
            edtpntEnd.SmartFormat(codeFunc.EndPoint);
        }

        public void GenerateArgumentNullCheck()
        {
            CodeParameter paramVar = GetCurrentCodeElement<CodeParameter>(vsCMElement.vsCMElementParameter);
            if (paramVar == null)
            {
                return;
            }

            CodeFunction codeFunc = paramVar.Parent as CodeFunction;

            AddCodeToFunction(codeFunc, "\n");
            GenerateParameterNullCheck(codeFunc, paramVar);
        }

        public void GenerateArgumentNullChecks()
        {
            CodeFunction codeFunc = GetCurrentCodeElement<CodeFunction>(vsCMElement.vsCMElementFunction);
            if (codeFunc == null)
            {
                return;
            }

            if (codeFunc.Parameters.Count < 1)
            {
                return;
            }

            AddCodeToFunction(codeFunc, "\n");

            foreach (CodeElement cp in codeFunc.Parameters)
            {
                CodeParameter paramVar = cp as CodeParameter;
                GenerateParameterNullCheck(codeFunc, paramVar);
            }

            EditPoint edtPnt = codeFunc.GetStartPoint(vsCMPart.vsCMPartBody).CreateEditPoint();
            edtPnt.SmartFormat(codeFunc.StartPoint);
            edtPnt.SmartFormat(codeFunc.EndPoint);
        }

        private void GenerateParameterNullCheck(CodeFunction func, CodeParameter paramVar)
        {
            StringBuilder cfNullArgCode = new StringBuilder();

            EditPoint edtPnt = ((CodeFunction)paramVar.Parent).GetStartPoint(vsCMPart.vsCMPartBody).CreateEditPoint();

            if (paramVar.Type.TypeKind == vsCMTypeRef.vsCMTypeRefCodeType)
            {
                cfNullArgCode.AppendLine("if(" + paramVar.Name + " == null) throw new ArgumentNullException(\"" + paramVar.Name + "\");");
            }
            else if (paramVar.Type.TypeKind == vsCMTypeRef.vsCMTypeRefString)
            {
                cfNullArgCode.AppendLine("if(string.IsNullOrEmpty(" + paramVar.Name + ")) throw new ArgumentNullException(\"" + paramVar.Name + "\");");
            }

            AddCodeToFunction(func, cfNullArgCode.ToString());
            edtPnt.SmartFormat(func.StartPoint);
            edtPnt.SmartFormat(func.EndPoint);
        }

    }
}
